/*
 * StrVec.cpp
 *
 *  Created on: 2020年12月1日
 *      Author: san
 */

#include "StrVec.h"

// 静态对象使用时，需在对应的源文件中声明
std::allocator<std::string> StrVec::alloc;

StrVec::StrVec(const StrVec &rhs)
{
	// 拷贝构造函数
	auto new_data = alloc_n_copy(rhs.begin(), rhs.end());
	elements = new_data.first;
	first_free = cap = new_data.second;
}

StrVec::StrVec(StrVec &&sv) noexcept :
		elements(std::move(sv.elements)), first_free(std::move(sv.first_free)), cap(std::move(sv.cap))
{
	std::cout << "StrVec::StrVec(StrVec &&sv)" << std::endl;
	sv.elements = sv.first_free = sv.cap = nullptr;
}

StrVec &StrVec::operator=(StrVec rhs)
{
	// 重载赋值运算符
	swap(*this, rhs);
	return *this;
}

void StrVec::push_back(const std::string &s)
{
	chk_n_alloc();
	alloc.construct(first_free++, s);
};

std::pair<std::string*, std::string*> StrVec::alloc_n_copy(const std::string *b, const std::string *e)
{
	// 分配内存， 并拷贝一个给定范围内的元素

	// 分配空间保存给定范围中的元素
	auto data = alloc.allocate(e - b);
	// 初始化并返回一个pair
	return {data, std::uninitialized_copy(b, e, data)};
}

void StrVec::free()
{
	// 销毁元素并释放内存
	if (elements)
	{
		for (auto p = first_free; p != elements;)
		{
			// 执行beg所指对象的析构函数， 但不释放内存
			alloc.destroy(--p);
		}
		alloc.deallocate(elements, size());
	}
}

void StrVec::reallocate()
{
	// 获取更多空间并拷贝已有元素
	auto new_capacity = size() ? 2 * size() : 1;
//	auto new_data = alloc.allocate(new_capacity);
	auto first = alloc.allocate(new_capacity);

	// 移动元素
	// 普通
//	auto dest = new_data;
//	auto elem = elements;
//	for (std::size_t i = 0; i < size(); ++i)  // 循环结束后dest指向first_free
//		alloc.construct(dest++, std::move(*elem++));

	// 使用移动迭代器
	auto last = std::uninitialized_copy(
			std::make_move_iterator(begin()), std::make_move_iterator(end()), first);
	free();  // 释放旧的存储空间
	// 更新我们的数据结构，执行新元素
	elements = first;
	first_free = last;
	cap = elements + new_capacity;
}

void StrVec::alloc_n_move(std::size_t cacpcity)
{
	auto new_data = alloc.allocate(cacpcity);

	// 移动元素
	auto dest = new_data;
	auto elem = elements;
	for (std::size_t i = 0; i < size(); ++i)  // 循环结束后dest指向first_free
		alloc.construct(dest++, std::move(*elem++));
	free();  // 释放旧的存储空间
	// 更新我们的数据结构，执行新元素
	elements = new_data;
	first_free = dest;
	cap = new_data + cacpcity;
}

void StrVec::reserve(std::size_t n)
{
	if (n <= capacity()) return;
	alloc_n_move(n);
}

void StrVec::resize(std::size_t n, const std::string &s)
{
	if (n > size())
	{
		if (n > capacity())
		{
			reserve(n);
		}

		for (std::size_t i = size(); i < n; ++i)
		{
			alloc.construct(first_free++, s);
		}
	}
	else if (n < size())
	{
		while ((elements + n) != first_free)
		{
			alloc.destroy(--first_free);
		}
	}
}

StrVec::~StrVec() {
	// TODO Auto-generated destructor stub
	free();
}

